<?php
namespace app\api\controller;
//use App\libs\HttpUtils\HttpUtils;
use app\common\controller\Api;
class WxPay
{
    const url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    const key = "KVhc625UKtu6s094iwoOZJcYho7QT15u";
    const appid = "wxd3ed1291e43598cd";
    const mch_id = "1602911873";
//    const total_fee = "1";

    const notify_url = "https://www.yunzhuke.net/api/index/wxxml";
    const notify_urlchongzhi = "https://www.yunzhuke.net/api/index/wxxmlchongzhi";
    const notify_urlactivity = "https://www.yunzhuke.net/api/index/wxxmlactivity";
    const notify_urlcard = "https://www.yunzhuke.net/api/index/wxxmlcard";

    const body = "住宿费";
    const body2 = "充值";
    const body3 = "办卡";
    const body5 = "活动";
    /**
     * 微信统一下单 所有参数为必填项 数据传输格式为xml 提交方式POST 其他可选项参照微信官方文档
     * @param url 统一下单地址
     * @param key API密钥 微信支付平台自定义
     * @param appid 小程序appid 微信公众平台获取
     * @param mch_id 商户号 微信支付平台获取
     * @param total_fee 金额 单位:分  作者写的东西金额是固定的，可作为参数传入函数
     * @param notify_url 异步接收微信支付结果通知的回调地址
     * @param nonce_str  随机字符串，长度要求在32位以内 下方已给出方法str_rand()
     * @param sign 通过签名算法计算得出的签名值 签名算法getSignTemp()：1.参数名ASCII码从小到大排序（字典序）2.如果参数的值为空不参与签名；3.参数名区分大小写 4.验证调用返回或微信主动通知签名时，传送的sign参数不参与签名，将生成的签名与该sign值作校验。
     * @param out_trade_no 商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一
     * @param openid 用户对应小程序的openid
     * @param body 商品描述 如:腾讯充值中心-QQ会员充值
     * @param trade_type 小程序取值如下：JSAPI 其他支付参照官方文档
     */
    public static function PrePay($out_trade_no,$openid,$price){

        $nonce_str=self::str_rand();      //生成随机32位字符串
        $SignTemp=self::getSignTemp($nonce_str,$openid,$out_trade_no,$price);  // 生成签名
        $data=[
            "appid"=>self::appid,     //appid
            "mch_id"=>self::mch_id, //商户号
            "nonce_str"=>$nonce_str,  //随机字符串
            "sign"=>$SignTemp,    //签名
            "body"=>self::body,   //商品描述
            "out_trade_no"=>$out_trade_no, //订单号
            "total_fee"=>$price,   //金额
            "trade_type"=>"JSAPI",  //支付类型 小程序取值如下：JSAPI 其他支付参照官方文档
            "notify_url"=>self::notify_url,  //异步接收微信支付结果通知的回调地址
            "openid"=>$openid   //用户对应小程序的openid
        ];
        $result=self::curl(self::url,$params=self::XmlAndArray($data,"array"),$ispost=1,$https=1);//请求接口得到预支付信息，curl方法在前一篇文章已经贴出，参数必须为xml格式，方法已给出XmlAndArray()
        return self::XmlAndArray($result,"xml"); //转化为数组方便取值，返回结果
    }


    //配置活动支付回调
    public static function PrePayActivity($out_trade_no,$openid,$price){

        $nonce_str=self::str_rand();      //生成随机32位字符串
        $SignTemp=self::getSignActivity($nonce_str,$openid,$out_trade_no,$price);  // 生成签名

        $data=[
            "appid"=>self::appid,     //appid
            "mch_id"=>self::mch_id, //商户号
            "nonce_str"=>$nonce_str,  //随机字符串
            "sign"=>$SignTemp,    //签名
            "body"=>self::body5,   //商品描述
            "out_trade_no"=>$out_trade_no, //订单号
            "total_fee"=>$price,   //金额
            "trade_type"=>"JSAPI",  //支付类型 小程序取值如下：JSAPI 其他支付参照官方文档
            "notify_url"=>self::notify_urlactivity,  //异步接收微信支付结果通知的回调地址
            "openid"=>$openid   //用户对应小程序的openid
        ];
        $result=self::curl(self::url,$params=self::XmlAndArray($data,"array"),$ispost=1,$https=1);//请求接口得到预支付信息，curl方法在前一篇文章已经贴出，参数必须为xml格式，方法已给出XmlAndArray()


        return self::XmlAndArray($result,"xml"); //转化为数组方便取值，返回结果
    }



    public static function PrePaychongzhi($out_trade_no,$openid,$price){

        $nonce_str=self::str_rand();      //生成随机32位字符串
        $SignTemp=self::getSignTempchongzhi($nonce_str,$openid,$out_trade_no,$price);  // 生成签名

        $data=[
            "appid"=>self::appid,     //appid
            "mch_id"=>self::mch_id, //商户号
            "nonce_str"=>$nonce_str,  //随机字符串
            "sign"=>$SignTemp,    //签名
            "body"=>self::body2,   //商品描述
            "out_trade_no"=>$out_trade_no, //订单号
            "total_fee"=>$price,   //金额
            "trade_type"=>"JSAPI",  //支付类型 小程序取值如下：JSAPI 其他支付参照官方文档
            "notify_url"=>self::notify_urlchongzhi,  //异步接收微信支付结果通知的回调地址
            "openid"=>$openid   //用户对应小程序的openid
        ];
        $result=self::curl(self::url,$params=self::XmlAndArray($data,"array"),$ispost=1,$https=1);//请求接口得到预支付信息，curl方法在前一篇文章已经贴出，参数必须为xml格式，方法已给出XmlAndArray()


        return self::XmlAndArray($result,"xml"); //转化为数组方便取值，返回结果
    }


    public static function PrePaycard($out_trade_no,$openid,$price){

        $nonce_str=self::str_rand();      //生成随机32位字符串
        $SignTemp=self::getSignTempcard($nonce_str,$openid,$out_trade_no,$price);  // 生成签名

        $data=[
            "appid"=>self::appid,     //appid
            "mch_id"=>self::mch_id, //商户号
            "nonce_str"=>$nonce_str,  //随机字符串
            "sign"=>$SignTemp,    //签名
            "body"=>self::body3,   //商品描述
            "out_trade_no"=>$out_trade_no, //订单号
            "total_fee"=>$price,   //金额
            "trade_type"=>"JSAPI",  //支付类型 小程序取值如下：JSAPI 其他支付参照官方文档
            "notify_url"=>self::notify_urlcard,  //异步接收微信支付结果通知的回调地址
            "openid"=>$openid   //用户对应小程序的openid
        ];
        $result=self::curl(self::url,$params=self::XmlAndArray($data,"array"),$ispost=1,$https=1);//请求接口得到预支付信息，curl方法在前一篇文章已经贴出，参数必须为xml格式，方法已给出XmlAndArray()


        return self::XmlAndArray($result,"xml"); //转化为数组方便取值，返回结果
    }





    public static function getPaySign($prepay_id,$nonce_str){
        $timeStamp=time();//时间戳
        $PaySign=md5("appId=".self::appid."&nonceStr=".$nonce_str."&package=prepay_id=".$prepay_id."&signType=MD5&timeStamp=".(string)$timeStamp."&key=".self::key);//生成支付签名，严格按照官方要求填写参数
        return ["PaySign"=>$PaySign,"timeStamp"=>$timeStamp];//返回签名以及时间戳
    }



    public static function getSignActivity($nonce_str,$openid,$out_trade_no,$price){
        $SignTemp="appid=".self::appid."&body=".self::body5."&mch_id=".self::mch_id."&nonce_str=".$nonce_str."&notify_url=".self::notify_urlactivity."&openid=".$openid."&out_trade_no=".$out_trade_no."&total_fee=".$price."&trade_type=JSAPI";//生成下单签名，严格按照官方要求填写参数
        $SignTemp=md5($SignTemp."&key=".self::key);
        return $SignTemp; //返回签名，统一下单需要调用
    }

    public static function getSignTemp($nonce_str,$openid,$out_trade_no,$price){
        $SignTemp="appid=".self::appid."&body=".self::body."&mch_id=".self::mch_id."&nonce_str=".$nonce_str."&notify_url=".self::notify_url."&openid=".$openid."&out_trade_no=".$out_trade_no."&total_fee=".$price."&trade_type=JSAPI";//生成下单签名，严格按照官方要求填写参数
        $SignTemp=md5($SignTemp."&key=".self::key);
        return $SignTemp; //返回签名，统一下单需要调用
    }


    public static function getSignTempchongzhi($nonce_str,$openid,$out_trade_no,$price){
        $SignTemp="appid=".self::appid."&body=".self::body2."&mch_id=".self::mch_id."&nonce_str=".$nonce_str."&notify_url=".self::notify_urlchongzhi."&openid=".$openid."&out_trade_no=".$out_trade_no."&total_fee=".$price."&trade_type=JSAPI";//生成下单签名，严格按照官方要求填写参数
        $SignTemp=md5($SignTemp."&key=".self::key);
        return $SignTemp; //返回签名，统一下单需要调用
    }


    public static function getSignTempcard($nonce_str,$openid,$out_trade_no,$price){
        $SignTemp="appid=".self::appid."&body=".self::body3."&mch_id=".self::mch_id."&nonce_str=".$nonce_str."&notify_url=".self::notify_urlcard."&openid=".$openid."&out_trade_no=".$out_trade_no."&total_fee=".$price."&trade_type=JSAPI";//生成下单签名，严格按照官方要求填写参数
        $SignTemp=md5($SignTemp."&key=".self::key);
        return $SignTemp; //返回签名，统一下单需要调用
    }
    /**
     * 数组与XML互转 方便取数据
     * @param $data
     * @param $type 转换对象
     * return 数组或XML
     */


    public static function curl($url, $params = false, $ispost = 0, $https = 0)
    {
        $httpInfo = array();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json; charset=utf-8'
            )
        );
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($https) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
        }
        if ($ispost) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
            curl_setopt($ch, CURLOPT_URL, $url);
        } else {
            if ($params) {
                if (is_array($params)) {
                    $params = http_build_query($params);
                }
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }
        $response = curl_exec($ch);
        if ($response === FALSE) {
            return false;
        }
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
        curl_close($ch);
        return $response;
    }



    private static function XmlAndArray($data,$type)
    {
        if(!$data){
            return false;
        }
        else if($type=="xml"){
            libxml_disable_entity_loader(true);
            $values = json_decode(json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $values;
        }
        else if($type=="array"){
            $xml="<xml>";
            foreach ($data as $key=>$val){

                $xml.="<".$key.">".$val."</".$key.">";

            }
            $xml.="</xml>";
            return $xml;
        }
    }
    /**
     * 随机字符串生成
     * @param $length 字符串长度
     * @param $char  字符集
     * return $string 随机字符串
     */

    public static function str_rand($length = 32, $char = 'abcdefghijklmnopqrstuvwxyz0123456789') {
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str .= substr($char, mt_rand(0, strlen($char)-1), 1);
        }
        return $str;
    }
}
